package com.Managers;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.text.format.Time;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import com.shareup.R;
import com.utils.AlertDialogHelper;
import com.utils.CircularPictureClass;
import com.utils.CircularPictureClass.onCircularCompleted;


public class PictureManagerClass {

    private final static int y = 300;

    /**
     * Converts a immutable bitmap to a mutable bitmap. This operation doesn't
     * allocates
     * more memory that there is already allocated.
     * 
     * @param imgIn
     *            - Source image. It will be released, and should not be used
     *            more
     * @return a copy of imgIn, but muttable.
     */
    public static Bitmap convertToMutable(Bitmap imgIn) {

        try {
            // this is the file going to use temporally to save the bytes.
            // This file will not be a image, it will store the raw image data.
            File file = new File(Environment.getExternalStorageDirectory()
                        + File.separator + "temp.tmp");

            // Open an RandomAccessFile
            // Make sure you have added uses-permission
            // android:name="android.permission.WRITE_EXTERNAL_STORAGE"
            // into AndroidManifest.xml file
            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");

            // get the width and height of the source bitmap.
            int width = imgIn.getWidth();
            int height = imgIn.getHeight();
            Config type = imgIn.getConfig();

            // Copy the byte to the file
            // Assume source bitmap loaded using options.inPreferredConfig =
            // Config.ARGB_8888;
            FileChannel channel = randomAccessFile.getChannel();
            MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, imgIn.getRowBytes()
                        * height);
            imgIn.copyPixelsToBuffer(map);
            // recycle the source bitmap, this will be no longer used.
            imgIn.recycle();
            System.gc();// try to force the bytes from the imgIn to be released

            // Create a new bitmap to load the bitmap again. Probably the memory
            // will be available.
            imgIn = Bitmap.createBitmap(width, height, type);
            map.position(0);
            // load it back from temporary
            imgIn.copyPixelsFromBuffer(map);
            // close the temporary file and channel , then delete that also
            channel.close();
            randomAccessFile.close();

            // delete the temp file
            file.delete();

        }
        catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        catch (IOException e) {
            e.printStackTrace();
        }

        return imgIn;
    }

    public static Bitmap createDrawableFromView(Context context, View view) {

        DisplayMetrics displayMetrics = new DisplayMetrics();
        ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
        view.measure(displayMetrics.widthPixels, displayMetrics.heightPixels);
        view.layout(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels);
        view.buildDrawingCache();
        Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(bitmap);
        view.draw(canvas);

        return bitmap;
    }

    @SuppressWarnings("resource")
    public static byte[] getBytesFromFile(File file) throws IOException {

        InputStream is = new FileInputStream(file);

        // Get the size of the file
        long length = file.length();

        // You cannot create an array using a long type.
        // It needs to be an int type.
        // Before converting to an int type, check
        // to ensure that file is not larger than Integer.MAX_VALUE.
        if (length > Integer.MAX_VALUE) {
            // File is too large
        }

        // Create the byte array to hold the data
        byte[] bytes = new byte[(int) length];

        // Read in the bytes
        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length
                    && (numRead = is.read(bytes, offset, bytes.length
                                - offset)) >= 0) {
            offset += numRead;
        }

        // Ensure all the bytes have been read in
        if (offset < bytes.length) {
            throw new IOException("Could not completely read file "
                        + file.getName());
        }

        // Close the input stream and return bytes
        is.close();
        // delete the file

        return bytes;
    }

    public static void getCircularBitmap(Bitmap bmp, onCircularCompleted callback) {

        CircularPictureClass pg = new CircularPictureClass(bmp, null, callback);
        pg.execute();
    }

    public static void getResizedForCover(Uri path,Context context,OnCoverCompleted callback) {
        CreateCover cv = new CreateCover(context, callback);
        cv.execute(path);

    }

    public static Bitmap ImageResize(Bitmap bmp) {

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] bitmapdata = bos.toByteArray();
        ByteArrayInputStream bs = new ByteArrayInputStream(bitmapdata);

        InputStream in = null;

        //
        try {
            final int IMAGE_MAX_SIZE = 150000; // 1.5MP
            in = bs;
            // Decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(in, null, o);
            in.close();
            int scale = 1;
            while ((o.outWidth * o.outHeight)
                        * (1 / Math.pow(scale, 2)) > IMAGE_MAX_SIZE) {
                scale++;
            }

            Bitmap b = bmp;
            in = bs;
            if (scale > 1) {
                scale--;
                // scale to max possible inSampleSize that still yields an image
                // larger than target
                o = new BitmapFactory.Options();
                o.inSampleSize = scale;
                b = BitmapFactory.decodeStream(in, null, o);
                // resize to desired dimensions
                int height = b.getHeight();
                int width = b.getWidth();
                //
                //
                double y = Math.sqrt(IMAGE_MAX_SIZE
                            / (((double) width) / height));
                double x = (y / height) * width;
                Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x, (int) y, true);
                b.recycle();
                b = scaledBitmap;
                //
                System.gc();
            }

            in.close();
            //

            //
            return b;
        }
        catch (IOException e) {
            Log.e("SCALEPOST_DOWNLOADER", "CROP_ACI: "
                        + e.getMessage(), e);
            //
            return null;
        }
    }

    public static Bitmap ImageResize(Uri uri, Context context) {

        InputStream in = null;
        ContentResolver mContentResolver = context.getContentResolver();
        //
        try {
            final int IMAGE_MAX_SIZE = 150000; // 1.5MP
            in = mContentResolver.openInputStream(uri);
            // Decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(in, null, o);

            int scale = 1;
            in.close();
            while ((o.outWidth * o.outHeight)
                        * (1 / Math.pow(scale, 2)) > IMAGE_MAX_SIZE) {
                scale++;
            }

            Bitmap b = null;

            in = mContentResolver.openInputStream(uri);
            if (scale > 1) {
                scale--;
                // scale to max possible inSampleSize that still yields an image
                // larger than target
                o = new BitmapFactory.Options();
                o.inSampleSize = scale;
                b = BitmapFactory.decodeStream(in, null, o);
                // resize to desired dimensions
                int height = b.getHeight();
                int width = b.getWidth();
                //
                //
                double y = Math.sqrt(IMAGE_MAX_SIZE
                            / (((double) width) / height));
                double x = (y / height) * width;
                Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x, (int) y, true);
                b.recycle();
                b = scaledBitmap;
                //
                System.gc();
            }
            else {
                b = BitmapFactory.decodeStream(in);
            }
            in.close();
            //
            //
            return b;
        }
        catch (IOException e) {
            Log.e("SCALEPOST_DOWNLOADER", "CROP_ACI: "
                        + e.getMessage(), e);
            //
            return null;
        }
    }

    public static Bitmap ImageResizeMinimum(Bitmap bmp) {

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] bitmapdata = bos.toByteArray();
        ByteArrayInputStream bs = new ByteArrayInputStream(bitmapdata);

        InputStream in = null;

        //
        try {
            final int IMAGE_MAX_SIZE = 50000; // 1.5MP
            in = bs;
            // Decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(in, null, o);
            in.close();
            int scale = 1;
            while ((o.outWidth * o.outHeight)
                        * (1 / Math.pow(scale, 2)) > IMAGE_MAX_SIZE) {
                scale++;
            }

            Bitmap b = bmp;
            in = bs;
            if (scale > 1) {
                scale--;
                // scale to max possible inSampleSize that still yields an image
                // larger than target
                o = new BitmapFactory.Options();
                o.inSampleSize = scale;
                b = BitmapFactory.decodeStream(in, null, o);
                // resize to desired dimensions
                int height = b.getHeight();
                int width = b.getWidth();
                //
                //
                double y = Math.sqrt(IMAGE_MAX_SIZE
                            / (((double) width) / height));
                double x = (y / height) * width;
                Bitmap scaledBitmap = Bitmap.createScaledBitmap(b, (int) x, (int) y, true);
                b.recycle();
                b = scaledBitmap;
                //
                System.gc();
            }

            in.close();
            //

            //
            return b;
        }
        catch (IOException e) {
            Log.e("SCALEPOST_DOWNLOADER", "CROP_ACI: "
                        + e.getMessage(), e);
            //
            return null;
        }
    }

    public static void scalePostImage(int width, int height, ImageView view) {

        WindowManager wm = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();

        Point size = new Point();
        display.getSize(size);

        int intendedWidth = size.x;
        int originalWidth = width;
        int originalHeight = height;
        float scale = (float) intendedWidth / originalWidth;
        int newHeight = Math.round(originalHeight * scale);

        if (newHeight < y) {
            newHeight = y;
        }

        view.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
        view.getLayoutParams().width = intendedWidth;
        view.getLayoutParams().height = newHeight;
    }
  
    
    private static Bitmap fastblur(Bitmap sentBitmap, int radius) {

        // Stack Blur v1.0 from
        // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
        //
        // Java Author: Mario Klingemann <mario at quasimondo.com>
        // http://incubator.quasimondo.com
        // created Feburary 29, 2004
        // Android port : Yahel Bouaziz <yahel at kayenko.com>
        // http://www.kayenko.com
        // ported april 5th, 2012

        // This is a compromise between Gaussian Blur and Box blur
        // It creates much better looking blurs than Box Blur, but is
        // 7x faster than my Gaussian Blur implementation.
        //
        // I called it Stack Blur because this describes best how this
        // filter works internally: it creates a kind of moving stack
        // of colors whilst scanning through the image. Thereby it
        // just has to add one new block of color to the right side
        // of the stack and remove the leftmost color. The remaining
        // colors on the topmost layer of the stack are either added on
        // or reduced by one, depending on if they are on the right or
        // on the left side of the stack.
        //
        // If you are using this algorithm in your code please add
        // the following line:
        //
        // Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>

        Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);

        if (radius < 1) {
            return (null);
        }

        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        int[] pix = new int[w * h];

        bitmap.getPixels(pix, 0, w, 0, 0, w, h);

        int wm = w - 1;
        int hm = h - 1;
        int wh = w * h;
        int div = radius + radius + 1;

        int r[] = new int[wh];
        int g[] = new int[wh];
        int b[] = new int[wh];
        int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
        int vmin[] = new int[Math.max(w, h)];

        int divsum = (div + 1) >> 1;
        divsum *= divsum;
        int dv[] = new int[256 * divsum];
        for (i = 0; i < 256 * divsum; i++) {
            dv[i] = (i / divsum);
        }

        yw = yi = 0;

        int[][] stack = new int[div][3];
        int stackpointer;
        int stackstart;
        int[] sir;
        int rbs;
        int r1 = radius + 1;
        int routsum, goutsum, boutsum;
        int rinsum, ginsum, binsum;

        for (y = 0; y < h; y++) {
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
            for (i = -radius; i <= radius; i++) {
                p = pix[yi + Math.min(wm, Math.max(i, 0))];
                sir = stack[i + radius];
                sir[0] = (p & 0xff0000) >> 16;
                sir[1] = (p & 0x00ff00) >> 8;
                sir[2] = (p & 0x0000ff);
                rbs = r1 - Math.abs(i);
                rsum += sir[0] * rbs;
                gsum += sir[1] * rbs;
                bsum += sir[2] * rbs;
                if (i > 0) {
                    rinsum += sir[0];
                    ginsum += sir[1];
                    binsum += sir[2];
                }
                else {
                    routsum += sir[0];
                    goutsum += sir[1];
                    boutsum += sir[2];
                }
            }
            stackpointer = radius;

            for (x = 0; x < w; x++) {

                r[yi] = dv[rsum];
                g[yi] = dv[gsum];
                b[yi] = dv[bsum];

                rsum -= routsum;
                gsum -= goutsum;
                bsum -= boutsum;

                stackstart = stackpointer - radius + div;
                sir = stack[stackstart % div];

                routsum -= sir[0];
                goutsum -= sir[1];
                boutsum -= sir[2];

                if (y == 0) {
                    vmin[x] = Math.min(x + radius + 1, wm);
                }
                p = pix[yw + vmin[x]];

                sir[0] = (p & 0xff0000) >> 16;
                sir[1] = (p & 0x00ff00) >> 8;
                sir[2] = (p & 0x0000ff);

                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];

                rsum += rinsum;
                gsum += ginsum;
                bsum += binsum;

                stackpointer = (stackpointer + 1) % div;
                sir = stack[(stackpointer) % div];

                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];

                rinsum -= sir[0];
                ginsum -= sir[1];
                binsum -= sir[2];

                yi++;
            }
            yw += w;
        }
        for (x = 0; x < w; x++) {
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
            yp = -radius * w;
            for (i = -radius; i <= radius; i++) {
                yi = Math.max(0, yp) + x;

                sir = stack[i + radius];

                sir[0] = r[yi];
                sir[1] = g[yi];
                sir[2] = b[yi];

                rbs = r1 - Math.abs(i);

                rsum += r[yi] * rbs;
                gsum += g[yi] * rbs;
                bsum += b[yi] * rbs;

                if (i > 0) {
                    rinsum += sir[0];
                    ginsum += sir[1];
                    binsum += sir[2];
                }
                else {
                    routsum += sir[0];
                    goutsum += sir[1];
                    boutsum += sir[2];
                }

                if (i < hm) {
                    yp += w;
                }
            }
            yi = x;
            stackpointer = radius;
            for (y = 0; y < h; y++) {
                // Preserve alpha channel: ( 0xff000000 & pix[yi] )
                pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16)
                            | (dv[gsum] << 8) | dv[bsum];

                rsum -= routsum;
                gsum -= goutsum;
                bsum -= boutsum;

                stackstart = stackpointer - radius + div;
                sir = stack[stackstart % div];

                routsum -= sir[0];
                goutsum -= sir[1];
                boutsum -= sir[2];

                if (x == 0) {
                    vmin[y] = Math.min(y + r1, hm) * w;
                }
                p = x + vmin[y];

                sir[0] = r[p];
                sir[1] = g[p];
                sir[2] = b[p];

                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];

                rsum += rinsum;
                gsum += ginsum;
                bsum += binsum;

                stackpointer = (stackpointer + 1) % div;
                sir = stack[stackpointer];

                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];

                rinsum -= sir[0];
                ginsum -= sir[1];
                binsum -= sir[2];

                yi += w;
            }
        }

        bitmap.setPixels(pix, 0, w, 0, 0, w, h);

        return (bitmap);
    }

    public static class CreateBlurAsync extends AsyncTask<String, String, Drawable> {

        private OnBlurCompleted callback;

        private Context context;

        private String path;

        private int radio;

        private boolean reverse;

        private boolean userProfile;

        private View view;

        public CreateBlurAsync(int radio, View viewToChange,
                    String path) {

            super();
            this.radio = radio;
            this.view = viewToChange;
            this.context = view.getContext();
            this.path = path;
        }

        public CreateBlurAsync(int radio, View viewToChange,
                    String path, OnBlurCompleted callback) {

            super();
            this.radio = radio;
            this.view = viewToChange;
            this.context = view.getContext();
            this.path = path;
            this.callback = callback;
        }

        public void setReverse(boolean reverse) {

            this.reverse = reverse;
        }

        public void setUserProfile(boolean userProfile) {

            this.userProfile = userProfile;
        }

        @Override
        protected Drawable doInBackground(String... nothing) {

            if (!reverse) {
                Bitmap bm = PictureManagerClass.ImageResize(Uri.fromFile(new File(path)), context);
                if (radio > 0) {
                    Bitmap blur = fastblur(bm, radio);
                    return new BitmapDrawable(context.getResources(), blur);
                }
                return new BitmapDrawable(context.getResources(), bm);
            }

            Drawable change;
            if (view instanceof ImageView)
                change = ((ImageView) view).getDrawable();
            else
                change = view.getBackground();

            return change;

        }

        @SuppressWarnings("deprecation")
        @Override
        protected void onPostExecute(Drawable result) {

            ColorDrawable ColorD = new ColorDrawable(view.getContext().getResources().getColor(R.color.main));

            if (userProfile)
                ColorD = new ColorDrawable(view.getContext().getResources().getColor(R.color.profile_rec));

            Drawable[] cambios = new Drawable[2];

            if (!reverse) {

                cambios[0] = ColorD;

                cambios[1] = result;
            }
            else {

                cambios[0] = result;

                cambios[1] = ColorD;

            }

            TransitionDrawable trans = new TransitionDrawable(cambios);

            if (view instanceof ImageView)
                ((ImageView) view).setImageDrawable(trans);
            else
                view.setBackgroundDrawable(trans);

            trans.startTransition(400);

            //
            if (callback != null)
                callback.Completed();

        }

    }

    public static class CreateCover extends AsyncTask<Uri,String,byte[]>
    {

    	private OnCoverCompleted callback;
    	private AlertDialog progress;
    	private Context context;
 
		public CreateCover(Context context,OnCoverCompleted callback) {
			super();
			this.callback = callback;
			this.context = context;
		}

		@Override
		protected void onPostExecute(byte[] result) {
			
			progress.dismiss();
			 
			if(callback!=null)
				callback.Completed(result);
			
		
		}

		@Override
		protected void onPreExecute() {
			
			progress = AlertDialogHelper.setProgressDialog(progress, context.getString(R.string.dialog_creating_cover), context);
            progress.show();
		}

		@Override
		protected byte[] doInBackground(Uri... params) {

			String path = new File(params[0].getPath()).getAbsolutePath();
			Log.e("PATH", path);
	        Bitmap in = null;
	        Bitmap out = null;
	        Time now = new Time();
	        now.setToNow();
	        String name = now.hour + "" + now.minute + now.second
	                    + ".jpg";
	        DirManagerClass.setNameCutPicture(name);
	        String filepath = DirManagerClass.getNameCutPicture();
	        byte[] data;
	        FileOutputStream fOut;

	        try {

	            File file = new File(filepath);

	            if (path != null) {

	                in = BitmapFactory.decodeFile(path);
	                int width = in.getWidth();
	                int height = in.getHeight();
	                float scaleWidth = ((float) in.getWidth() / 2)
	                            / width;
	                float scaleHeight = ((float) in.getHeight() / 2)
	                            / height;
	                // CREATE A MATRIX FOR THE MANIPULATION
	                Matrix matrix = new Matrix();
	                // RESIZE THE BIT MAP
	                matrix.postScale(scaleWidth, scaleHeight);

	                // "RECREATE" THE NEW BITMAP
	                out = Bitmap.createBitmap(in, 0, 0, width, height, matrix, false);

	                fOut = new FileOutputStream(file);
	                out.compress(CompressFormat.PNG, 0, fOut);
	                fOut.flush();
	                fOut.close();
	                out.recycle();
	                in.recycle();
	            }

	            FileInputStream fin = new FileInputStream(file);
	            data = new byte[(int) file.length()];
	            fin.read(data);
	            fin.close();
	            file.delete();

	            return data;

	        }
	        catch (Exception x) {
	            Log.e("UPLOADPM", x.getMessage() + "");
	            return null;

	        }
		}
    	
    }
    public interface OnBlurCompleted {

        void Completed();
    }
    public interface OnCoverCompleted
    {
    	void Completed(byte[] result);
    }

}
